import { navigationRef } from '@/core/router/router'
import { eventStore } from '@/core/tools/eventStore'
import React, { FC, Fragment, createContext, memo, useContext, useEffect, useState } from 'react'

const Context = createContext(null)
const ContextRoot = createContext(null)
type Props = {
  /** 子组件 */
  children?: React.ReactNode
  renderToRoute?: boolean
}

export const PortalRootProvider = memo((props: Props) => {
  /** 保存Consumer组件中的children以渲染  */
  const [rootList, setRootList] = useState([])
  useEffect(() => {
    const subscribe = eventStore.subscribe('portal', ({ type, el }) => {
      if (type === 'render') {
        setRootList((value) => value.concat(el))
      } else {
        setRootList((value) => value.filter((item) => item !== el))
      }
    })
    return () => {
      subscribe?.()
    }
  }, [])
  return (
    <ContextRoot.Provider value={{ setRootList, rootList }}>
      {props.children}
      {rootList.map((el, index) => {
        return <Fragment key={index}>{el}</Fragment>
      })}
    </ContextRoot.Provider>
  )
})

export const PortalRouteProvider = memo((props: Props) => {
  /** 保存Consumer组件中的children以渲染  */
  const [list, setList] = useState([])
  const getRouteKey = () => (navigationRef.isReady() ? navigationRef?.getCurrentRoute?.()?.key : undefined)
  useEffect(() => {
    const subscribe = eventStore.subscribe('portalRoute', ({ type, el }) => {
      if (type === 'render') {
        setList((value) => value.concat({ el, key: getRouteKey() }))
      } else {
        setList((value) => value.filter((item) => item.key !== getRouteKey()))
      }
    })
    return () => {
      subscribe?.()
    }
  }, [])
  return (
    <Context.Provider value={{ setList, list }}>
      {props.children}
      {list
        .filter((each) => each.key === getRouteKey())
        .map((el, index) => {
          return <Fragment key={index}>{el.el}</Fragment>
        })}
    </Context.Provider>
  )
})

type ConsumerProps = {
  renderToRoute?: boolean
  children: React.ReactNode
}

export const Consumer = (props: ConsumerProps) => {
  const { children, renderToRoute } = props
  const { setList, setRootList } = useContext(renderToRoute ? Context : ContextRoot)

  const getRouteKey = () => (navigationRef.isReady() ? navigationRef?.getCurrentRoute?.()?.key : undefined)
  useEffect(() => {
    if (renderToRoute) {
      setList((value) => value.concat({ el: children, key: getRouteKey() }))
    } else {
      setRootList((value) => value.concat(children))
    }
    return () => {
      if (renderToRoute) {
        setList((value) => value.filter((item) => item.key !== getRouteKey()))
      } else {
        setRootList((value) => value.filter((item) => item !== children))
      }
    }
  }, [setList, children])
  return null
}

const portal = {
  render: (children, options) => {
    eventStore.publish(options?.renderToRoute ? 'portalRoute' : 'portal', { type: 'render', el: children })
    return children
  },
  remove: (children, options) => {
    return eventStore.publish(options?.renderToRoute ? 'portalRoute' : 'portal', {
      type: 'remove',
      el: children,
    })
  },
}

export function withPortal<P = unknown>(Component: FC<P>) {
  return (props?: P, options?: { renderToRoute: boolean }) => {
    const render = portal.render(<Component {...props} />, options)
    const unmount = () => portal.remove(render, options)
    return unmount
  }
}
